# set up the level
import pygame
from support import import_csv_layouts,import_cut_graphics
from settings import tile_size,screen_width,screen_height
from tiles import StaticTile
from enzyme import Enzyme
from playerr import Player
from particles import ParticleEffect
from random import randint,choice

class Level:
    def __init__(self,level_data,surface,change_coins):
        # general setups
        self.display_surface = surface
        self.world_shift = 0
        self.current_x = None
        self.status = 0

        # ui
        self.change_coins = change_coins

        # csv layouts
        # terrain setup 
        terrain_layout = import_csv_layouts(level_data['terrain'])
        self.terrain_sprites = self.create_tile_group(terrain_layout,'terrain')

        # tooth setup
        tooth_layout = import_csv_layouts(level_data['tooth'])
        self.tooth_sprites = self.create_tile_group(tooth_layout, 'tooth')

        # player
        player_layout = import_csv_layouts(level_data['player'])
        self.player = pygame.sprite.GroupSingle()
        self.goal = pygame.sprite.GroupSingle()
        self.player_setup(player_layout)

        # enzyme setup
        self.enzyme_sprites = pygame.sprite.Group()
        self.enzyme_gravity = 0.2
        self.enzyme_speed = randint(3,4)
        self.flag = choice((1,-1))
        self.enzyme_direction = -1
        self.show = True

        # dust
        self.dust_sprite = pygame.sprite.GroupSingle()
        self.player_on_ground = False
    
    def create_tile_group(self, layout, type):
        sprite_group = pygame.sprite.Group()

        for row_index,row in enumerate(layout):
            for col_index, val in enumerate(row):
                if val != '-1':
                    x = col_index * tile_size
                    y = row_index * tile_size

                    if type == 'terrain':
                        terrain_tile_list = import_cut_graphics('../graphics/terrain/terrain_tiles.png')
                        tile_surface = terrain_tile_list[int(val)]
                        sprite = StaticTile(tile_size,x,y,tile_surface)       

                    if type == 'tooth':
                        tooth_tile_list = import_cut_graphics('../graphics/decorations/crates/tooth.png')
                        tile_surface = tooth_tile_list[int(val)]
                        sprite = StaticTile(tile_size,x,y,tile_surface)
                    # add sprites    
                    sprite_group.add(sprite)

        return sprite_group

    # begining and ending square
    def player_setup(self,layout):
        for row_index,row in enumerate(layout):
            for col_index, val in enumerate(row):
                x = col_index * tile_size
                y = row_index * tile_size
                if val == '0':
                    sprite = Player((x,y), self.display_surface, self.create_jump_particles)
                    self.player.add(sprite)
                if val == '1':
                    goal_surface = pygame.image.load('../graphics/character/player/player2.png').convert_alpha()
                    sprite = StaticTile(tile_size,x,y,goal_surface)
                    self.goal.add(sprite)

    def create_jump_particles(self,pos):
        if self.player.sprite.facing_right:  
            pos -= pygame.math.Vector2(10,5)# let the dust right below the player
        else:
            pos += pygame.math.Vector2(10,-5)
        jump_particle_sprite = ParticleEffect(pos,'jump')
        self.dust_sprite.add(jump_particle_sprite)

    # seperate x from y
    def horizontal_movement_collision(self):  # make judgements of where the collide is
        player = self.player.sprite
        player.rect.x += player.direction.x * player.speed
        
        for sprite in self.terrain_sprites.sprites():
            if sprite.rect.colliderect(player.rect):
                # moving left
                if player.direction.x < 0: 
                    player.rect.left = sprite.rect.right
                    player.on_left = True
                    # tells the x position of where the collision occurs
                    self.current_x = player.rect.left  
                elif player.direction.x > 0:
                    player.rect.right = sprite.rect.left
                    player.on_right = True
                    self.current_x = player.rect.right

        # avoiding the overlap(touching the left wall or moving to right)
        if player.on_left and (player.rect.left < self.current_x or player.direction.x >= 0): 
            player.on_left = False
        if player.on_right and (player.rect.right > self.current_x or player.direction.x <= 0):
            player.on_right = False
            
    def vertical_movement_collision(self): 
        player = self.player.sprite
        player.apply_gravity()
        
        for sprite in self.terrain_sprites.sprites():
            if sprite.rect.colliderect(player.rect):
                if player.direction.y > 0:  
                    player.rect.bottom = sprite.rect.top
                    player.direction.y = 0 #stand on the floor(cancle out the gravity)
                    player.on_ground = True
                elif player.direction.y < 0:
                    player.rect.top = sprite.rect.bottom
                    player.direction.y = 0 #bomb down(cancle out y direction movement)
                    player.on_ceiling = True

        # turning the attributes off
        if player.on_ground and player.direction.y < 0 or player.direction.y > 1:
            player.on_ground = False
        if player.on_ceiling and player.direction.y > 0:   # no need to judge direction < 0
            player.on_ceiling = False

    def scroll_x(self):  # not let the player run out of the screen
        player = self.player.sprite
        player_x = player.rect.centerx  # get the player's center position
        direction_x = player.direction.x

        if player_x < screen_width / 4 and direction_x < 0: # moving to the left
            self.world_shift = 8
            player.speed = 0
        elif player_x > screen_width - (screen_width / 4) and direction_x >0:
            self.world_shift = -8
            player.speed = 0
        else:
            self.world_shift = 0
            player.speed = 8

    def get_player_on_ground(self):
        if self.player.sprite.on_ground:
            self.player_on_ground = True
        else:
            self.player_on_ground = False

    def create_landing_dust(self):
        # before collision: not on the ground; after the collision: on the ground
        if not self.player_on_ground and self.player.sprite.on_ground and not self.dust_sprite.sprites():  
            if self.player.sprite.facing_right:
                offset = pygame.math.Vector2(0,15)
            else:
                offset = pygame.math.Vector2(0,15)
            fall_dust_particle = ParticleEffect(self.player.sprite.rect.midbottom - offset,'land')
            self.dust_sprite.add(fall_dust_particle)

    def check_tooth_collisions(self):
        collided_teeth = pygame.sprite.spritecollide(self.player.sprite, self.tooth_sprites, False)
        if collided_teeth:
            for tooth in collided_teeth:
                tooth_center = tooth.rect.centery
                tooth_bottom = tooth.rect.bottom
                player_top = self.player.sprite.rect.top
                if tooth_bottom > player_top > tooth_center and self.player.sprite.direction.y <= 0:
                    self.player.sprite.direction.y = 5
                    ez_sprite = Enzyme((tooth.rect.centerx, tooth.rect.centery - 40),screen_height)
                    self.enzyme_sprites.add(ez_sprite)
                    tooth.kill()

    def enzyme_movey(self):
        # all the sprites need to move down
        if self.enzyme_sprites:
            for alien in self.enzyme_sprites:
                self.enzyme_direction += self.enzyme_gravity
                alien.rect.y += self.enzyme_direction
    
    def enzyme_movex(self):
        # all the sprites need to move horizontally 
        if self.enzyme_sprites:
            for alien in self.enzyme_sprites:
                alien.rect.x += (randint(2,4) * self.flag)
                alien.rect.x += self.world_shift

    # image reverse(depend on speed)
    def enzyme_reverse_image(self):
        for enzyme in self.enzyme_sprites.sprites():
            if self.enzyme_speed <= 0:
                enzyme.image = pygame.transform.flip((pygame.image.load('../graphics/enzyme/enzyme.png').convert_alpha()),True,False)

    # enzyme collisions
    def enzyme_y_collision(self):
        for enzyme in self.enzyme_sprites.sprites():
            if pygame.sprite.spritecollide(enzyme, self.terrain_sprites, False):
                self.enzyme_direction = 0

    def enzyme_x_collision(self):
        for enzyme in self.enzyme_sprites.sprites():
            if pygame.sprite.spritecollide(enzyme, self.terrain_sprites, False) and self.enzyme_direction != 0:
                self.enzyme_speed = 0

    def check_enzyme_collision(self):
        collided_enzyme = pygame.sprite.spritecollide(self.player.sprite, self.enzyme_sprites,False)
        if collided_enzyme:
            for enzyme in collided_enzyme:
                self.change_coins(1)
                enzyme.kill()

    # game over screen
    def check_death(self):
        if self.player.sprite.rect.top > screen_height:
            self.status = -1
    
    def check_win(self):
        if pygame.sprite.spritecollide(self.player.sprite,self.goal,False):
            self.status = 1

    def run(self):
        # run the entire game
        self.terrain_sprites.draw(self.display_surface)
        self.terrain_sprites.update(self.world_shift)

        # tooth
        self.tooth_sprites.draw(self.display_surface)
        self.tooth_sprites.update(self.world_shift)

        # enzyme
        self.enzyme_sprites.draw(self.display_surface)

        # dust particles
        self.dust_sprite.update(self.world_shift)
        self.dust_sprite.draw(self.display_surface)

        # player sprites
        self.goal.update(self.world_shift)
        self.goal.draw(self.display_surface)
        self.player.update()
        self.horizontal_movement_collision()
        self.vertical_movement_collision()
        self.scroll_x()
        self.player.draw(self.display_surface)
        
        # enzyme sprites
        self.check_tooth_collisions()
        self.enzyme_movey()
        self.enzyme_movex()
        self.enzyme_reverse_image()
        self.enzyme_y_collision()
        self.enzyme_x_collision()
        self.check_enzyme_collision()

        # game ui
        self.check_death()
        self.check_win()